using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ObjectPoolManager : SingleMonoScene<ObjectPoolManager>
{
    Dictionary<string, Queue<GameObject>> pool;
    public Dictionary<string, Queue<GameObject>> Pool => pool;
    public const bool IS_USE_RESOURCE = false;

    public AssetBundle defaultBundle;
    public Dictionary<string,AssetBundle> bundles;
    private void Awake()
    {
        Init();
    }
    void Init() {
        pool = new Dictionary<string, Queue<GameObject>>();
    }
    public void InitBundles(AssetBundle defaultBundle, Dictionary<string, AssetBundle> bundles) {
        this.defaultBundle = defaultBundle;
        this.bundles = bundles;
    }
    public T DePool<T>(string name, bool isUseResource = IS_USE_RESOURCE,string path=null) where T : BasePoolElement{
        if (pool.ContainsKey(name) && pool[name] != null && pool[name].Count>0)
        {
            Debug.Log("depool from  pool");
            GameObject go = pool[name].Dequeue();
            BasePoolElement script = go.GetComponent<BasePoolElement>();
            T poolElement = null;
            if (!script is T)
            {
                DestroyImmediate(script);
                poolElement = go.AddComponent<T>();
            }
            else
            {
                poolElement = script as T;
            }
            poolElement.DePool(name);
            return poolElement;
        }
        else
        {
            Debug.Log("depool from  Instantiate");
            GameObject go = PoolInstantiate(name, isUseResource, path);
            T poolElement = go.AddComponent<T>();
            poolElement.DePool(name);
            return poolElement;
        }
    }
    public void EnPool(BasePoolElement element)
    {
        Debug.Log(element.PoolName);
       
        if (!pool.ContainsKey(element.PoolName))
        {
            pool.Add(element.PoolName, new Queue<GameObject>());
        }
        element.EnPool();
        pool[element.PoolName].Enqueue(element.gameObject);

    }
    GameObject PoolInstantiate(string name, bool isUseResource = IS_USE_RESOURCE,string path =null) {
        GameObject go = null;
  
        if (isUseResource)
        {
            if (path!=null)
            {
                go = Resources.Load<GameObject>($"{path}/{name}");
            }
            else
            {
                go = Resources.Load<GameObject>(name);
            }
        }
        else
        {
            if (path == null && defaultBundle != null)
            {
                go = defaultBundle.LoadAsset<GameObject>(name);
            }
            else
            {
                go = bundles[path].LoadAsset<GameObject>(name);
            }
        }
        return Instantiate<GameObject>(go);
    }
    private void OnDestroy()
    {
        if (pool != null)
        {
            foreach (var item in pool.Values)
            {
                while (item.Count > 0)
                {
                    GameObject obj = item.Dequeue();
                    Destroy(obj);
                }
            }
            pool.Clear();
        }
    }
    public class Debug
    {
        public static void LogError(object s)
        {
            //UnityEngine.Debug.LogError(s);
        }
        public static void Log(object s)
        {
            //UnityEngine.Debug.Log(s);
        }
    }
}

public abstract class BasePoolElement:MonoBehaviour{

    bool isInPool;
    string poolName;
    public virtual void PoolInit() { 
    
    }
    public bool IsInPool => isInPool;
    public string PoolName => poolName;
    public virtual void EnPool() {
        isInPool = true;
        this.enabled = false;
        gameObject.SetActive(false);
    }

    public virtual void DePool(string poolName) {
        this.poolName = poolName;
        isInPool = false;
        this.enabled = true;
        gameObject.SetActive(true);
        PoolInit();
    }
}

